package com.geyue.common.util;

import org.nutz.lang.random.R;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.DecimalFormat;

public class FileUtil {

	/**
	 * 上传文件
	 * @param request
	 * @return
	 * @throws Exception 
	 */
	public static String upload(HttpServletRequest request)
			throws Exception {
		// 设置上下方文
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
				request.getSession().getServletContext());

		String baseUrl = request.getSession().getServletContext().getRealPath("/");

		if (multipartResolver.isMultipart(request)) {
			MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
			MultipartFile file = multiRequest.getFile("file");
			if (file.isEmpty())
				return null;
			// 文件名称
			String fileName = file.getOriginalFilename();
			// 生成新的文件名称
			String realName = R.UU16() + fileName;
			// 组成拥有真实路径的一个完整的地址字符串
			String fileUrl = baseUrl + File.separator + realName;
			// 根据这个完整地址字符串，生成提交文件所要保存到的目标文件或目录的对象
			File targetFile = new File(fileUrl);
			// 判断目标文件或目录的对象是否已经存在
			if (!targetFile.exists())
				targetFile.mkdirs();
			// 传送文件到目标对象
			file.transferTo(targetFile);

			return fileUrl;
		}
		return null;
	}
	

	/**
	 * 获取文件大小 K 或M
	 * 
	 * @param size
	 * @return
	 */
	public static String getFileSize(long size) {
		DecimalFormat df2 = new DecimalFormat("###.00");
		double num = (double) size / 1024;
		if (num < 1024) {
			return df2.format(num) + "K";
		} else {
			return df2.format(num / 1024) + "M";
		}
	}

	/**
	 * 复制文件
	 * 
	 * @param sourceFile
	 * @param targetFile
	 * @throws IOException
	 */
	public static void copyFile(File sourceFile, File targetFile) throws IOException {
		// 新建文件输入流并对它进行缓冲
		InputStream input = new FileInputStream(sourceFile);
		copyFile(input, targetFile);
	}

	/**
	 * 复制文件
	 * 
	 * @param sourceFilePath
	 * @param targetFilePath
	 * @throws IOException
	 */
	public static void copyFile(String sourceFilePath, String targetFilePath) throws IOException {
		File source = new File(sourceFilePath);
		// 新建文件输入流并对它进行缓冲
		InputStream input = new FileInputStream(source);

		copyFile(input, new File(targetFilePath));
	}

	/**
	 * 复制文件
	 * 
	 * @param input
	 * @param targetFile
	 * @throws IOException
	 */
	public static void copyFile(InputStream input, File targetFile) throws IOException {
		// 新建文件输入流并对它进行缓冲
		BufferedInputStream inBuff = new BufferedInputStream(input);

		// 新建文件输出流并对它进行缓冲
		FileOutputStream output = new FileOutputStream(targetFile);
		BufferedOutputStream outBuff = new BufferedOutputStream(output);

		// 缓冲数组
		byte[] b = new byte[1024 * 10];
		int len;
		while ((len = inBuff.read(b)) != -1) {
			outBuff.write(b, 0, len);
		}
		// 刷新此缓冲的输出流
		outBuff.flush();
		// 关闭流
		inBuff.close();
		outBuff.close();
		output.close();
		input.close();
	}

	/**
	 * 复制文件夹
	 * 
	 * @param sourceDir
	 * @param targetDir
	 * @throws IOException
	 */
	public static void copyDirectiory(String sourceDir, String targetDir) throws IOException {
		// 新建目标目录
		new File(targetDir).mkdirs();
		// 获取源文件夹当前下的文件或目录
		File[] file = (new File(sourceDir)).listFiles();
		for (int i = 0; i < file.length; i++) {
			if (file[i].isFile()) {
				// 源文件
				File sourceFile = file[i];
				// 目标文件
				File targetFile = new File(new File(targetDir).getAbsolutePath() + File.separator + file[i].getName());
				copyFile(sourceFile, targetFile);
			}
			if (file[i].isDirectory()) {
				// 准备复制的源文件夹
				String dir1 = sourceDir + "/" + file[i].getName();
				// 准备复制的目标文件夹
				String dir2 = targetDir + "/" + file[i].getName();
				copyDirectiory(dir1, dir2);
			}
		}
	}

	/**
	 * 删除目录（文件夹）以及目录下的文件
	 * 
	 * @param sourcePath
	 *            被删除目录的文件路径
	 * @return 目录删除成功返回true，否则返回false
	 */
	public static boolean deleteDirectory(String sourcePath) {
		// 如果sPath不以文件分隔符结尾，自动添加文件分隔符
		if (!sourcePath.endsWith(File.separator)) {
			sourcePath = sourcePath + File.separator;
		}
		File dirFile = new File(sourcePath);
		// 如果dir对应的文件不存在，或者不是一个目录，则退出
		if (!dirFile.exists() || !dirFile.isDirectory()) {
			return false;
		}
		boolean flag = true;
		// 删除文件夹下的所有文件(包括子目录)
		File[] files = dirFile.listFiles();
		for (int i = 0; i < files.length; i++) {
			// 删除子文件
			if (files[i].isFile()) {
				flag = deleteFile(files[i].getAbsolutePath());
				if (!flag)
					break;
			} // 删除子目录
			else {
				flag = deleteDirectory(files[i].getAbsolutePath());
				if (!flag)
					break;
			}
		}
		if (!flag)
			return false;
		// 删除当前目录
		if (dirFile.delete()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 删除单个文件
	 * 
	 * @param sourcePath
	 *            被删除文件的路径
	 * @return 单个文件删除成功返回true，否则返回false
	 */
	public static boolean deleteFile(String sourcePath) {
		File file = new File(sourcePath);
		// 路径为文件且不为空则进行删除
		if (file.isFile() && file.exists()) {
			file.delete();
			return true;
		}
		return false;
	}

	/**
	 * 
	 * 根据路径删除指定的目录或文件，无论存在与否
	 * 
	 * @param sourcePath
	 *            要删除的目录或文件
	 * @return 删除成功返回 true，否则返回 false。
	 */
	public static boolean deleteFolder(String sourcePath) {
		boolean flag = false;
		File file = new File(sourcePath);
		// 判断目录或文件是否存在
		if (!file.exists()) {
			// 不存在返回 false
			return flag;
		} else {
			// 判断是否为文件
			if (file.isFile()) {
				// 为文件时调用删除文件方法
				return deleteFile(sourcePath);
			} else {
				// 为目录时调用删除目录方法
				return deleteDirectory(sourcePath);
			}
		}
	}

	/**
	 * 获取file数组中最大的一个文件
	 * 
	 * @param files
	 * @return
	 */
	public static File maxFile(File[] files) {
		File tempFile = null;
		long size = 0;
		for (File file : files) {
			if (size < file.length()) {
				size = file.length();
				tempFile = file;
			}
		}
		return tempFile;
	}

	/**
	 * 获取file数组中最小的一个文件
	 * 
	 * @param files
	 * @return
	 */
	public static File minFile(File[] files) {
		File tempFile = null;
		Long size = null;
		for (File file : files) {
			if (null == size) {
				size = file.length();
				tempFile = file;
				continue;
			}

			if (size > file.length()) {
				size = file.length();
				tempFile = file;
				continue;
			}

		}
		return tempFile;
	}

	
	/**
	 * 编码转换
	 * 
	 * @param toCharset
	 *            要转换的编码
	 * @param path
	 *            要转换的文件路径
	 * @return
	 * @throws Exception
	 */
	public static String encoding(String toCharset, String path) throws Exception {
		BytesEncodingDetect encode = new BytesEncodingDetect();
		File srcFile = new File(path);
		int index = encode.detectEncoding(srcFile);
		String charset = BytesEncodingDetect.javaname[index];
		// 编码相同，无需转码
		if (charset.equalsIgnoreCase(toCharset)) {
			return "编码一样，无需转换";
		}

		InputStream in = new FileInputStream(path);

		BufferedReader br = new BufferedReader(new InputStreamReader(in, charset));

		StringBuffer sb = new StringBuffer();
		String s1;
		while ((s1 = br.readLine()) != null) {
			String s = URLEncoder.encode(s1, toCharset);
			sb.append(s + "\r\n");// 一行+回车
		}

		br.close();
		srcFile.delete();// 删除原来文件
		// 重新以新编码写入文件并返回值
		File newfile = new File(path);// 重新建原来的文件
		newfile.createNewFile();
		OutputStream out = new FileOutputStream(newfile);
		OutputStreamWriter writer = new OutputStreamWriter(out, toCharset);
		BufferedWriter bw = new BufferedWriter(writer);
		bw.write(URLDecoder.decode(sb.toString(), toCharset));
		String result = URLDecoder.decode(sb.toString(), toCharset);
		bw.flush();// 刷到文件中
		bw.close();
		return result;
	}


	/**
	 * 文件转换为BASE64 编码
	 * @param path
	 * @return
	 * @throws Exception
	 */
	public static String encodeBase64(String path) throws Exception{
		File file = new File(path);
		String asBase64 = DatatypeConverter.printBase64Binary(convertBytes(file));
		return asBase64;
	}

	/**
	 * 文件转换字节
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static byte[] convertBytes(File file) throws IOException {
		InputStream is = new FileInputStream(file);
		long length = file.length();
		byte[] bytes = new byte[(int) length];
		int offset = 0;
		int numRead = 0;
		while (offset < bytes.length
				&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
			offset += numRead;
		}

		if (offset < bytes.length) {
			is.close();
			throw new IOException("Could not completely read file " + file.getName());
		}
		is.close();
		return bytes;
	}

}
